package router

import (
	"go.uber.org/zap"
	"live-core/core"
	"live-core/logging"
	"log"
	"time"

	"github.com/geekerstar/libv/format/mp4f"
	"golang.org/x/net/websocket"
)

func StreamMSE(ws *websocket.Conn) {
	defer func() {
		err := ws.Close()
		if err != nil {
			logging.ZapLog.Error(err.Error(),
				zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
				zap.String("call", "Close"))
		}
		log.Println("客户端退出")
	}()
	if !core.StreamManager.ChannelExist(ws.Request().FormValue("uuid"), ws.Request().FormValue("channel")) {

		logging.ZapLog.Error(core.ErrorStreamNotFound.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "ChannelExist"))
		return
	}
	core.StreamManager.ChannelRun(ws.Request().FormValue("uuid"), ws.Request().FormValue("channel"))
	err := ws.SetWriteDeadline(time.Now().Add(5 * time.Second))
	if err != nil {

		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "SetWriteDeadline"))

		return
	}
	cid, ch, _, err := core.StreamManager.ClientAdd(ws.Request().FormValue("uuid"), ws.Request().FormValue("channel"), core.MSE)
	if err != nil {
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "ClientAdd"))

		return
	}
	defer core.StreamManager.ClientDelete(ws.Request().FormValue("uuid"), cid, ws.Request().FormValue("channel"))
	codecs, err := core.StreamManager.ChannelCodecs(ws.Request().FormValue("uuid"), ws.Request().FormValue("channel"))
	if err != nil {
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "StreamCodecs"))

		return
	}
	muxerMSE := mp4f.NewMuxer(nil)
	err = muxerMSE.WriteHeader(codecs)
	if err != nil {
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "WriteHeader"))

		return
	}
	meta, init := muxerMSE.GetInit(codecs)
	err = websocket.Message.Send(ws, append([]byte{9}, meta...))
	if err != nil {
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "Send"))

		return
	}
	err = websocket.Message.Send(ws, init)
	if err != nil {
		logging.ZapLog.Error(err.Error(),
			zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
			zap.String("call", "Send"))

		return
	}
	var videoStart bool
	controlExit := make(chan bool, 10)
	go func() {
		defer func() {
			controlExit <- true
		}()
		for {
			var message string
			err := websocket.Message.Receive(ws, &message)
			if err != nil {
				logging.ZapLog.Error(err.Error(),
					zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
					zap.String("call", "Receive"))

				return
			}
		}
	}()
	noVideo := time.NewTimer(10 * time.Second)
	for {
		select {
		case <-controlExit:
			logging.ZapLog.Error("客户端消费者退出",
				zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
				zap.String("call", "controlExit"))
			return
		case <-noVideo.C:
			logging.ZapLog.Error(core.ErrorStreamNoVideo.Error(),
				zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
				zap.String("call", "ErrorStreamNoVideo"))
			return
		case pck := <-ch:
			if pck.IsKeyFrame {
				noVideo.Reset(10 * time.Second)
				videoStart = true
			}
			if !videoStart {
				continue
			}
			ready, buf, err := muxerMSE.WritePacket(*pck, false)
			if err != nil {
				logging.ZapLog.Error(err.Error(),
					zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
					zap.String("call", "WritePacket"))

				return
			}
			if ready {
				err := ws.SetWriteDeadline(time.Now().Add(10 * time.Second))
				if err != nil {
					logging.ZapLog.Error(err.Error(),
						zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
						zap.String("call", "SetWriteDeadline"))
					return
				}
				err = websocket.Message.Send(ws, buf)
				if err != nil {
					logging.ZapLog.Error(err.Error(),
						zap.String("stream", ws.Request().FormValue("uuid")), zap.String("channel", ws.Request().FormValue("channel")),
						zap.String("call", "Send"))
					return
				}
			}
		}
	}
}
